home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0039_QSort for DELPHI.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-11-22  |  5.7 KB  |  235 lines

  1. unit Qsort;
  2.  
  3. {TQSort by Mike Junkin 10/19/95.
  4.  DoQSort routine adapted from Peter Szymiczek's QSort procedure which
  5.  was presented in issue#8 of The Unofficial Delphi Newsletter.}
  6.  
  7. interface
  8.  
  9. uses
  10.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  11.   Forms, Dialogs;
  12.  
  13. type
  14.   TSwapEvent = procedure (Sender : TObject; e1,e2 : word) of Object;
  15.   TCompareEvent = procedure (Sender: TObject; e1,e2 : word; var Action : integer) of Object;
  16.  
  17.   TQSort = class(TComponent)
  18.   private
  19.     FCompare : TCompareEvent;
  20.     FSwap : TSwapEvent;
  21.   public
  22.     procedure DoQSort(Sender: TObject; uNElem: word);
  23.   published
  24.     property Compare : TCompareEvent read FCompare write FCompare;
  25.  
  26.     property Swap : TSwapEvent read FSwap write FSwap;
  27.   end;
  28.  
  29. procedure Register;
  30.  
  31. implementation
  32.  
  33. procedure Register;
  34. begin
  35.   RegisterComponents('Mikes', [TQSort]);
  36. end;
  37.  
  38. procedure TQSort.DoQSort(Sender: TObject; uNElem: word);
  39. { uNElem - number of elements to sort }
  40.  
  41.   procedure qSortHelp(pivotP: word; nElem: word);
  42.   label
  43.     TailRecursion,
  44.     qBreak;
  45.   var
  46.     leftP, rightP, pivotEnd, pivotTemp, leftTemp: word;
  47.     lNum: word;
  48.     retval: integer;
  49.   begin
  50.     retval := 0;
  51.     TailRecursion:
  52.       if (nElem <= 2) then
  53.  
  54.         begin
  55.           if (nElem = 2) then
  56.             begin
  57.               rightP := pivotP +1;
  58.               FCompare(Sender,pivotP,rightP,retval);
  59.               if (retval > 0) then Fswap(Sender,pivotP,rightP);
  60.             end;
  61.           exit;
  62.         end;
  63.       rightP := (nElem -1) + pivotP;
  64.       leftP :=  (nElem shr 1) + pivotP;
  65.       { sort pivot, left, and right elements for "median of 3" }
  66.       FCompare(Sender,leftP,rightP,retval);
  67.       if (retval > 0) then Fswap(Sender,leftP, rightP);
  68.       FCompare(Sender,leftP,pivotP,retval);
  69.  
  70.       if (retval > 0) then Fswap(Sender,leftP, pivotP)
  71.       else 
  72.         begin
  73.           FCompare(Sender,pivotP,rightP,retval);
  74.           if retval > 0 then Fswap(Sender,pivotP, rightP);
  75.         end;
  76.       if (nElem = 3) then
  77.         begin
  78.           Fswap(Sender,pivotP, leftP);
  79.           exit;
  80.         end;
  81.       { now for the classic Horae algorithm }
  82.       pivotEnd := pivotP + 1;
  83.       leftP := pivotEnd;
  84.       repeat
  85.         FCompare(Sender,leftP, pivotP,retval);
  86.         while (retval <= 0) do
  87.           begin
  88.  
  89.             if (retval = 0) then
  90.               begin
  91.                 Fswap(Sender,leftP, pivotEnd);
  92.                 Inc(pivotEnd);
  93.               end;
  94.             if (leftP < rightP) then
  95.               Inc(leftP)
  96.             else
  97.               goto qBreak;
  98.             FCompare(Sender,leftP, pivotP,retval);
  99.           end; {while}
  100.         while (leftP < rightP) do
  101.           begin
  102.             FCompare(Sender,pivotP, rightP,retval);
  103.             if (retval < 0) then
  104.               Dec(rightP)
  105.  
  106.             else
  107.               begin
  108.                 FSwap(Sender,leftP, rightP);
  109.                 if (retval <> 0) then
  110.                   begin
  111.                     Inc(leftP);
  112.                     Dec(rightP);
  113.                   end;
  114.                 break;
  115.               end;
  116.           end; {while}
  117.  
  118.       until (leftP >= rightP);
  119.     qBreak:
  120.       FCompare(Sender,leftP,pivotP,retval);
  121.       if (retval <= 0) then Inc(leftP);
  122.  
  123.       leftTemp := leftP -1;
  124.       pivotTemp := pivotP;
  125.       while ((pivotTemp < pivotEnd) and (leftTemp >= pivotEnd)) do
  126.         begin
  127.           Fswap(Sender,pivotTemp, leftTemp);
  128.           Inc(pivotTemp);
  129.           Dec(leftTemp);
  130.         end; {while}
  131.       lNum := (leftP - pivotEnd);
  132.       nElem := ((nElem + pivotP) -leftP);
  133.  
  134.       if (nElem < lNum) then
  135.         begin
  136.           qSortHelp(leftP, nElem);
  137.           nElem := lNum;
  138.         end
  139.       else
  140.         begin
  141.  
  142.           qSortHelp(pivotP, lNum);
  143.           pivotP := leftP;
  144.         end;
  145.       goto TailRecursion;
  146.     end; {qSortHelp }
  147.  
  148. begin
  149.   if Assigned(FCompare) and Assigned(FSwap) then
  150.   begin
  151.     if (uNElem < 2) then  exit; { nothing to sort }
  152.     qSortHelp(1, uNElem);
  153.   end;
  154. end; { QSort }
  155.  
  156. end. 
  157.  
  158. { demo }
  159.  
  160. unit Unit1;
  161.  
  162. interface
  163.  
  164. uses
  165.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  166.   Forms, Dialogs, Grids, Qsort, StdCtrls;
  167.  
  168. type
  169.   TForm1 = class(TForm)
  170.     QSort1: TQSort;
  171.     StringGrid1: TStringGrid;
  172.     Button1: TButton;
  173.     procedure FormCreate(Sender: TObject);
  174.     procedure QSort1Compare(Sender: TObject; e1, e2: Word; var Action: Integer);
  175.     procedure QSort1Swap(Sender: TObject; e1, e2: Word);
  176.     procedure Button1Click(Sender: TObject);
  177.   end;
  178.  
  179. var
  180.   Form1: TForm1;
  181.  
  182. implementation
  183.  
  184. {$R *.DFM}
  185.  
  186. procedure TForm1.FormCreate(Sender: TObject);
  187. begin
  188.  
  189.      with StringGrid1 do
  190.      begin
  191.           Cells[1,1] := 'the';
  192.           Cells[1,2] := 'brown';
  193.           Cells[1,3] := 'dog';
  194.           Cells[1,4] := 'bit';
  195.           Cells[1,5] := 'me';
  196.      end;
  197. end;
  198.  
  199. procedure TForm1.QSort1Compare(Sender: TObject; e1, e2: Word;
  200.   var Action: Integer);
  201. begin
  202.      with Sender as TStringGrid do
  203.     begin
  204.       if (Cells[1, e1] < Cells[1, e2]) then
  205.         Action := -1
  206.       else if (Cells[1, e1] > Cells[1, e2]) then
  207.  
  208.         Action := 1
  209.       else
  210.         Action := 0;
  211.     end; {with}
  212.  
  213. end;
  214.  
  215. procedure TForm1.QSort1Swap(Sender: TObject; e1, e2: Word);
  216. var
  217.   s: string[63];  { must be large enough to contain the longest string in the grid }
  218.   i: integer;
  219. begin
  220.   with Sender as TStringGrid do
  221.     for i := 0 to ColCount -1 do
  222.     begin
  223.       s := Cells[i, e1];
  224.       Cells[i, e1] := Cells[i, e2];
  225.       Cells[i, e2] := s;
  226.     end; {for}
  227.  
  228. end;
  229.  
  230. procedure TForm1.Button1Click(Sender: TObject);
  231. begin
  232.   QSort1.DoQSort(StringGrid1,STringGrid1.RowCount-1);
  233. end;
  234.  
  235. end.